package com.yupi.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yupi.project.common.ErrorCode;
import com.yupi.project.exception.BusinessException;
import com.yupi.project.model.entity.UserInterfaceInfo;
import com.yupi.project.service.UserInterfaceInfoService;
import com.yupi.project.mapper.UserInterfaceInfoMapper;
import org.springframework.stereotype.Service;

/**
* @author 张志远
* @description 针对表【user_interface_info(用户调用接口关系)】的数据库操作Service实现
* @createDate 2024-09-09 14:13:14
*/
@Service
public class UserInterfaceInfoServiceImpl extends ServiceImpl<UserInterfaceInfoMapper, UserInterfaceInfo>
    implements UserInterfaceInfoService{

    @Override
    public void validUserInterfaceInfo(UserInterfaceInfo userinterfaceInfo, boolean add) {

        // 判断接口信息对象是否为空,为空则抛出参数错误的异常
        if (userinterfaceInfo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }


        // 如果是添加操作,所有参数必须非空,否则抛出参数错误的异常
        if (add) {
            if (userinterfaceInfo.getInterfaceInfoId() <=0 || userinterfaceInfo.getUserId() <=0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"接口或用户不存在");
            }
        }
        // 如果接口名称不为空且长度大于50,抛出参数错误的异常,错误信息为"名称过长"
        // 本期写成<50,(没有解决),第二期视频中解决了
        if (userinterfaceInfo.getLeftNum() <0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "剩余参次数不能小于0");
        }
    }

    @Override
    public boolean invokeCount(long interfaceInfoId, long userId) {
        // 判断(其实这里还应该校验存不存在，这里就不用校验了，因为它不存在，也更新不到那条记录)
        if (interfaceInfoId <= 0 || userId <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 使用 UpdateWrapper 对象来构建更新条件
        UpdateWrapper<UserInterfaceInfo> updateWrapper = new UpdateWrapper<>();
        // 在 updateWrapper 中设置了两个条件：interfaceInfoId 等于给定的 interfaceInfoId 和 userId 等于给定的 userId。
        updateWrapper.eq("interfaceInfoId", interfaceInfoId);
        updateWrapper.eq("userId", userId);
        // setSql 方法用于设置要更新的 SQL 语句。这里通过 SQL 表达式实现了两个字段的更新操作：
        // leftNum=leftNum-1和totalNum=totalNum+1。意思是将leftNum字段减一，totalNum字段加一。
        updateWrapper.setSql("leftNum = leftNum - 1, totalNum = totalNum + 1");
        // 最后，调用update方法执行更新操作，并返回更新是否成功的结果
        return this.update(updateWrapper);

        //todo
        /*由于用户可能会瞬间调用大量接口次数，为了避免统计出错，需要涉及到事务和锁的知识。在这种情况下，如果我们是在分布式环境中运行的，那么可能需要使用分布式锁来保证数据的一致性。
        事务是一组操作的集合，要么全部成功，要么全部失败回滚。在这个场景中，我们希望在更新用户接口信息的时候，保证原子性，即要么用户接口信息全部更新成功，要么全部不更新。
        锁的作用是为了防止多个线程或进程同时修改同一个数据，造成数据不一致的情况。在分布式环境中，我们需要使用分布式锁来确保在多个节点上对数据的访问是互斥的。
        然而，在这里的代码中，并没有实现事务和锁的逻辑。这里只是演示了整体的流程，并没有具体实现细节。所以，如果要在实际项目中应用这个功能，还需要进一步考虑并实现事务和锁的机制，以确保数据的一致性和安全性。*/
    }

}




